using System;
using System.IO;
using System.Text;
using System.Xml;
using HenIT.Utilities;
using System.Diagnostics;
using System.Reflection;


//Credits: Original source and article
//http://grounding.co.za/blogs/romiko/archive/2008/03/24/automating-hosts-host-instances-and-adapter-handlers-configuration-in-biztalk-2006.aspx

namespace BiztalkConfigLoader
{
    public class Program
    {
        #region Privates
        private static XmlDocument doc = new XmlDocument();
        private static UTF8Encoding encoding = new UTF8Encoding();
        private static string logFile;
        private static string defaultUserName;
        private static string defaultPassword;
        private static string servername = ".";
        #endregion

        [STAThreadAttribute]
        public static void Main(string[] args)
        {
            //if (args.Length == 0)
            //{
            //    Main frm = new BiztalkConfigLoader.Main();

            //    frm.ShowDialog();
            //    return;
            //}
            string configFile = "BtsAdminConfiguration.xml";
            bool runRemove = false;
            if (CommandLineUtils.IsCommand(args, "-?", "/?", "-h", "/h"))
            {
                ShowHelp();
            }
            else
            {
                try
                {
                    logFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "BTSConfig" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".log");


                   
                    configFile = CommandLineUtils.GetDefault(args, configFile);
                    runRemove = CommandLineUtils.IsCommand(args, "-r", "/r");
                    defaultUserName = CommandLineUtils.GetCommand(args, "", "-u:", "/u:");
                    defaultPassword = CommandLineUtils.GetCommand(args, "", "-p:", "/p:");

                    
                   
                    Console.WriteLine("Close all running Biztalk Administration Consoles (or any other biztalk applications) and then press any key.");
                    Console.ReadKey();
                    //Load Configuration file
                    doc.Load(configFile);
                    if (args.Length == 1 && (args[0].Equals("-r") || args[0].Equals("/r")))
                    {
                        RemoveFirst();
                        return;
                    }
                    //Remove the old settings
                    if (runRemove)
                    {
                        RemoveFirst();
                        
                    }

                    AddHosts();
                    AddHostInstances();
                    AddAdapters();
                    Console.WriteLine("Do you want to automatically remove Default Hosts from the Adapters? (y/n)");
                    var key = Console.ReadKey().KeyChar.ToString().ToUpper();
                    if (key == "Y" || key == "J")
                    {



                        RemoveDefaultHosts();
                    }
                }
                catch (Exception e)
                {
                    WriteLog("Fatal Error : " + e.Message);
                }
                finally
                {
                    WriteLog("Done!!!");
                }
            }
#if DEBUG
            System.Threading.Thread.Sleep(5000); //wait a bit to see output in screen
#endif
        }

        private static void RemoveFirst()
        {
            RemoveAdapters();
            RemoveHostInstances();
            RemoveHosts();
        }

       

        private static void ShowHelp()
        {
            Console.WriteLine("Usage: BiztalkConfigLoader.exe [config file] [-r] [-u:username] [-p:password]");
            Console.WriteLine("  where");
            Console.WriteLine("     config file  : BizTalk XML configuration. Default BtsAdminConfiguration.xml");
            Console.WriteLine("     -r           : Remove previous settings first");
            Console.WriteLine("     -u:          : Default username used to run host instances");
            Console.WriteLine("     -p:          : default password used to run host instances");
        }

        private static void GetServername(ref string servername)
        {
            if (servername == "." || servername == "(local)")
            {
                servername = Environment.MachineName;
            }
        }

        #region Hosts
        private static void AddHosts()
        {
            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/Hosts/Host"))
            {
                string hostName = node.Attributes["hostname"].Value;
                string ntGroupName = node.Attributes["ntgroupname"].Value;
                bool isDefault = Convert.ToBoolean(node.Attributes["isdefault"].Value);
                bool hostTracking = Convert.ToBoolean(node.Attributes["hosttracking"].Value);
                bool authTrusted = Convert.ToBoolean(node.Attributes["authtrusted"].Value);
                int hostType = Convert.ToInt32(node.Attributes["hosttype"].Value);
                bool isHost32BitOnly = true;
                if (node.Attributes["ishost32bitonly"] != null)
                {
                    isHost32BitOnly = Convert.ToBoolean(node.Attributes["ishost32bitonly"].Value);
                }
                WriteLog("Adding host " + hostName);
                try
                {
                    BtsAdministration.AddHost(hostName, ntGroupName, isDefault, hostTracking, authTrusted, hostType, isHost32BitOnly);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void RemoveHosts()
        {
            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/Hosts/Host"))
            {
                string hostName = node.Attributes["hostname"].Value;
                WriteLog("Removing host " + hostName);
                try
                {
                    BtsAdministration.RemoveHost(hostName);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void RemoveDefaultHosts()
        {
            var inPRocessHost = "BizTalkServerApplication";
            var isolatedHost = "BizTalkServerIsolatedHost";

            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/Adapters/Adapter"))
            {

                var adaptername = node.Attributes["name"].Value;

                WriteLog("Processing Adapter: " + adaptername);
                BtsAdministration.RemoveReceiveHandler(adaptername, inPRocessHost);
                BtsAdministration.RemoveSendHandler(adaptername, inPRocessHost);
                BtsAdministration.RemoveReceiveHandler(adaptername, isolatedHost);


            }



            try
            {

                WriteLog("Trying to remove HostInstances !");
                BtsAdministration.RemoveHostInstance(servername, inPRocessHost);
                BtsAdministration.RemoveHostInstance(servername, isolatedHost);
                WriteLog("Trying to remove Hosts!This might go wrong");
                BtsAdministration.RemoveHost(inPRocessHost);
                BtsAdministration.RemoveHost(isolatedHost);

            }
            catch (Exception ex)
            {

                throw;
            }

           

        }
        #endregion

        #region Host instances
        private static void AddHostInstances()
        {
            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/HostInstances/HostInstance"))
            {
                 servername = node.Attributes["servername"].Value;
                GetServername(ref servername);
                string hostname = node.Attributes["hostname"].Value;
                string username = node.Attributes["username"].Value;
                if (username.Length == 0)
                    username = defaultUserName;
                string password = node.Attributes["password"].Value;
                if (password.Length == 0)
                    password = defaultPassword;
                bool startinstance = Convert.ToBoolean(node.Attributes["startinstance"].Value);
                WriteLog("Adding hostinstance " + hostname + " on " + servername);
                try
                {
                    if (startinstance)
                        WriteLog("and starting it...");
                    BtsAdministration.AddHostInstance(servername, hostname, username, password, startinstance);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void RemoveHostInstances()
        {
            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/HostInstances/HostInstance"))
            {
                string servername = node.Attributes["servername"].Value;
                GetServername(ref servername);
                string hostname = node.Attributes["hostname"].Value;
                WriteLog("Removing hostinstance " + hostname + " on " + servername);
                try
                {
                    BtsAdministration.RemoveHostInstance(servername, hostname);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        } 
        #endregion

        #region Adapters and handlers
        private static void AddAdapters()
        {
            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/Adapters/Adapter"))
            {
                string name = node.Attributes["name"].Value;
                string type = node.Attributes["type"].Value;
                string comment = node.Attributes["comment"].Value;
                WriteLog("Adding adapter " + name);
                try
                {
                    BtsAdministration.AddAdapter(name, type, comment);
                    WriteLog("  Succeeded");
                    AddReceiveHandlers(name, node);
                    AddSendHandlers(name, node);
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void AddReceiveHandlers(string adaptername, XmlNode adapterNode)
        {
            foreach (XmlNode node in adapterNode.SelectNodes("ReceiveHandler"))
            {
                string hostname = node.Attributes["hostname"].Value;

                

                WriteLog("Adding receive handler for host " + hostname);
                try
                {
                    BtsAdministration.AddReceiveHandler(adaptername, hostname);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void AddSendHandlers(string adaptername, XmlNode adapterNode)
        {
            foreach (XmlNode node in adapterNode.SelectNodes("SendHandler"))
            {

                bool isdefault = false;
                try
                {
                    Boolean.TryParse(node.Attributes["isdefault"].Value, out isdefault);
                }
                catch
                { isdefault = false; }
                string hostname = node.Attributes["hostname"].Value;
                WriteLog("Adding send handler for host " + hostname);
                try
                {
                    BtsAdministration.AddSendHandler(adaptername, hostname, isdefault);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void RemoveAdapters()
        {
            foreach (XmlNode node in doc.SelectNodes("BtsAdminConfiguration/Adapters/Adapter"))
            {
                string name = node.Attributes["name"].Value;
                WriteLog("Removing adapter " + name);
                try
                {
                    RemoveReceiveHandlers(name, node);
                    RemoveSendHandlers(name, node);
                    BtsAdministration.RemoveAdapter(name);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void RemoveReceiveHandlers(string adaptername, XmlNode adapterNode)
        {
            foreach (XmlNode node in adapterNode.SelectNodes("ReceiveHandler"))
            {
                string hostname = node.Attributes["hostname"].Value;
                WriteLog("Removing receive handler for host " + hostname);
                try
                {
                    BtsAdministration.RemoveReceiveHandler(adaptername, hostname);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        }

        private static void RemoveSendHandlers(string adaptername, XmlNode adapterNode)
        {
            foreach (XmlNode node in adapterNode.SelectNodes("SendHandler"))
            {
                string hostname = node.Attributes["hostname"].Value;
                WriteLog("Removing send handler for host " + hostname);
                try
                {
                    BtsAdministration.RemoveSendHandler(adaptername, hostname);
                    WriteLog("  Succeeded");
                }
                catch (Exception e)
                {
                    WriteLog("  Error " + e.Message);
                }
            }
        } 
        #endregion
        
        #region Write to log
        private static void WriteLog(string message)
        {
            Console.WriteLine(message);
            File.AppendAllText(logFile, message + Environment.NewLine, encoding);
        } 
        #endregion
    }
}